%%%-------------------------------------------------------------------
%%% @author
%%% @copyright (C) 2013, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 28. Okt 2013 18:13
%%%-------------------------------------------------------------------
-module(mst).

%% API
-import(werkzeug, [get_config_value/2, logging/2, timeMilliSecond/0, to_String/1,list2String/1]).
-export([start/1]).
-record( recordState, {nodeName, nighborDict, configListe, level, fragName, inBranch, testEdge, bestEdge, bestWeight, nodeState, findCount} ).

start(NodeName) ->
  NodeCfgName = list_to_atom((lists:concat([NodeName,".cfg"]))),
  {ok, ConfigListe} = file:consult(NodeCfgName),
  LogDatei = lists:concat([NodeName,".log"]),
  %logging(LogDatei,lists:concat([werkzeug:list2String(ConfigListe)," geladen. Zeit: ",timeMilliSecond(),".\r\n"])),
  NighborDict = koordinator:dict_init(ConfigListe),
  %logging(LogDatei,lists:concat([" Nachbarn: ",list2String(dict:to_list(NighborDict)),".\r\n"])),
  RecordState = #recordState{ nodeName = NodeName, nighborDict = NighborDict ,configListe = ConfigListe, nodeState = sleeping,
  level = 0, findCount = 0, testEdge = undefined, bestWeight = infinity},
  PID = spawn(fun() -> loop(RecordState, LogDatei) end),
  global:register_name(NodeName,PID),

  Zeit = lists:concat(["Startzeit: ",timeMilliSecond()]),
  logging(LogDatei,lists:concat([Zeit," mit PID ",pid_to_list(PID)," registriert mit Namen '",NodeName,"'.\r\n"])).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% startprog
%
%Knoten initialisieren
%%
loop(RecordState, LogDatei) ->
  %logging(LogDatei, lists:concat(["-----------------------------------------------\n"])),
  %logging(LogDatei, lists:concat([" RecordState nighborDict: ", werkzeug:list2String(dict:to_list(RecordState#recordState.nighborDict))," \n"])),

  %logging(LogDatei, lists:concat([" PROZTEST NighborDict ", werkzeug:list2String(dict:to_list(RecordState#recordState.nighborDict)) ," ", timeMilliSecond(),"\n"])),
  %logging(LogDatei, lists:concat(["--------Wartet auf Nachricht---------", timeMilliSecond(),"\n"])),
  receive
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-----INITIATE-----%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    {initiate,Level,FragName,NodeState,{Edge,Nodex,Nodey}} ->
      logging(LogDatei, lists:concat([" INIT RECEIVED von Kante ", Edge ," auf Level ", Level, " mit FrageName " , FragName, " und NodeState ", NodeState, " um ", timeMilliSecond()," \n"])),
      NewRecordState = RecordState#recordState{ level = Level, fragName = FragName, nodeState = NodeState, inBranch = {Edge,Nodex,Nodey}, bestEdge = undefined, bestWeight = infinity },  %%%%%prüfen parentedge
      EdgeBranches = koordinator:dict_getBranchEdges( NewRecordState#recordState.nighborDict, Edge),
      %logging(LogDatei, lists:concat([" INIT dict_getAllBranchEdges ", list2String(dict:to_list(AllEdgeBranches)),"\n"])),

      Fun = fun(Key, Value, Accu) ->
        {Values, _} = Value,
        Nodi = list_to_atom((lists:concat([Values]))),
        Node = global:whereis_name(Nodi),
        logging(LogDatei, lists:concat(["INITIATE zu Nodename ", Values ,"-Kante ",Key ," mit Node ",pid_to_list(Node) ," ", timeMilliSecond(),"\n"])),
        Node ! {initiate, Level, FragName , NodeState, {Key,NewRecordState#recordState.nodeName,Values}},

        if(NodeState == find) ->
          (Accu + 1);
        true ->
          Accu
        end
      end,

      NewFindCount = dict:fold(Fun, NewRecordState#recordState.findCount, EdgeBranches),
      NewNewRecordState = NewRecordState#recordState{findCount = NewFindCount},
      if( NodeState == find ) ->
        %logging(LogDatei, lists:concat([" INITIATE Nodestate ist FIND ", timeMilliSecond(),"\n"])),
        NewNewNewRecordState = prozTest(NewNewRecordState,LogDatei);
        true ->
          %logging(LogDatei, lists:concat([" INITIATE Nodestate ist nicht FIND ", timeMilliSecond(),"\n"])),
          NewNewNewRecordState = NewNewRecordState
      end,
      logging(LogDatei, lists:concat([" RecordState nighborDict: ", werkzeug:list2String(dict:to_list(NewNewNewRecordState#recordState.nighborDict))," \n"])),
      loop(NewNewNewRecordState, LogDatei);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-----TEST-----%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    {test,Level,FragName,{Edge,Nodex,Nodey}} ->
      %logging(LogDatei, lists:concat([" TEST RECEIVED von Kante ", Edge ," auf Level ", Level, " mit FrageName " , FragName, " um ", timeMilliSecond()," \n"])),
      if (RecordState#recordState.nodeState == sleeping) ->
        logging(LogDatei, lists:concat([" WAKEUP über TEST um ", timeMilliSecond(),"\n"])),
        %logging(LogDatei, lists:concat([(RecordState#recordState.nodeName), " wacht auf \n"])),
        TempRecordState = prozWakeup(RecordState, LogDatei);
        true ->
          TempRecordState = RecordState%,
          %logging(LogDatei, lists:concat(["TEST ist wach um ", timeMilliSecond(),"\n"]))
      end,

      %logging(LogDatei, lists:concat([Level," Level > ", TempRecordState#recordState.level, " recordState.level ", timeMilliSecond(),"\n"])),
      if (Level > TempRecordState#recordState.level) ->
        %logging(LogDatei, lists:concat([" Test Level > LevelNode", timeMilliSecond(),"\n"])),
        Nodi = TempRecordState#recordState.nodeName,
        Node = global:whereis_name(Nodi),
        %logging(LogDatei, lists:concat([" Nochmal TEST an sich selbst", timeMilliSecond(),"\n"])),
        Node ! {test,Level,FragName,{Edge, Nodex, Nodey}},
        loop(TempRecordState, LogDatei);


        true->
          %logging(LogDatei, lists:concat([" TEST  Level NICHT GRÖSSER LevelNode", timeMilliSecond(),"\n"])),
          logging(LogDatei, lists:concat([" TEST RECEIVED von Kante ", Edge ," auf Level ", Level, " mit FrageName " , FragName, " um ", timeMilliSecond()," \n"])),
          if (FragName /= TempRecordState#recordState.fragName)->
            %logging(LogDatei, lists:concat([" TEST  F!=FN", timeMilliSecond(),"\n"])),
            {ok,{Values,_}} = koordinator:dict_findEdgeNodeName(TempRecordState#recordState.nighborDict, Edge),
            Nodi = list_to_atom((lists:concat([Values]))),
            Node = global:whereis_name(Nodi),
            logging(LogDatei, lists:concat(["TEST Accept zu Nodename ", Values ," mit Node ",pid_to_list(Node) ," ", timeMilliSecond(),"\n"])),
            Node ! {accept,{Edge,TempRecordState#recordState.nodeName,Values}},
            NewNewRecordState = TempRecordState,%;
            loop(NewNewRecordState, LogDatei);

            true->
              %logging(LogDatei, lists:concat([" TEST  F=FN", timeMilliSecond(),"\n"])),
              {ok,{Values,State}} = koordinator:dict_findEdgeNodeName(TempRecordState#recordState.nighborDict, Edge),

              case(State == basic) of
                true ->
                  %logging(LogDatei, lists:concat(["TEST Edge ist BASIC", timeMilliSecond(),"\n"])),
                  NewNodeDict = koordinator:nodeDict_set(Edge,{Values,rejected},TempRecordState#recordState.nighborDict),
                  %logging(LogDatei, lists:concat([" TEST Edge ist BASIC Neue  NewNodeDict ", werkzeug:list2String(dict:to_list(NewNodeDict)) ," ", timeMilliSecond(),"\n"])),
                  NewRecordState = TempRecordState#recordState{nighborDict = NewNodeDict};
                false ->
                  %logging(LogDatei, lists:concat(["TEST Edge keine BASIC ", timeMilliSecond(),"\n"])),
                  NewRecordState = TempRecordState
              end,

              EdgeIsEqual = koordinator:isEdgeEqual(NewRecordState#recordState.testEdge, Edge),
              case(EdgeIsEqual) of
                true ->
                  %logging(LogDatei, lists:concat(["TEST Edges sind Equal", timeMilliSecond(),"\n"])),
                  NewNewRecordState = prozTest(NewRecordState, LogDatei);
                false ->
                  %logging(LogDatei, lists:concat(["TEST Edge sind nicht Equal", timeMilliSecond(),"\n"])),
                  Nodi = list_to_atom((lists:concat([Values]))),
                  Node = global:whereis_name(Nodi),
                  logging(LogDatei, lists:concat(["TEST Reject zu Nodename ", Values ," mit Node ",pid_to_list(Node) ," ", timeMilliSecond(),"\n"])),
                  Node ! {reject,{Edge,NewRecordState#recordState.nodeName,Values}},
                  NewNewRecordState = NewRecordState
              end,
              logging(LogDatei, lists:concat([" RecordState nighborDict: ", werkzeug:list2String(dict:to_list(NewNewRecordState#recordState.nighborDict))," \n"])),
              loop(NewNewRecordState, LogDatei)
          end
      %startprog(NewNewRecordState, LogDatei)
      end;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-----ACCEPT-----%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    {accept,{Edge,Nodex,Nodey}} ->
      logging(LogDatei, lists:concat([" ACCEPT RECEIVED von Kante ", Edge ," um ", timeMilliSecond()," \n"])),
      NewRecordState = RecordState#recordState{ testEdge = undefined },

      if(Edge < NewRecordState#recordState.bestWeight) ->
        %logging(LogDatei, lists:concat([" ACCEPT neue BestWeight von Kante ", Edge ," um ", timeMilliSecond()," \n"])),
        NewNewRecordState = NewRecordState#recordState{ bestEdge = {Edge,Nodex,Nodey}, bestWeight = Edge};
        true ->
          %logging(LogDatei, lists:concat([" ACCEPT keine neue BestWeight von Kante ", Edge ," um ", timeMilliSecond()," \n"])),
          NewNewRecordState =  NewRecordState
      end,

      NewNewNewRecordState = prozReport(NewNewRecordState, LogDatei),
      logging(LogDatei, lists:concat([" RecordState nighborDict: ", werkzeug:list2String(dict:to_list(NewNewNewRecordState#recordState.nighborDict))," \n"])),
      loop(NewNewNewRecordState, LogDatei);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-----REJECT-----%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    {reject,{Edge,_Nodex,_Nodey}} ->
      logging(LogDatei, lists:concat([" REJECT RECEIVED von Kante ", Edge ," um ", timeMilliSecond()," \n"])),
      {ok,{Values,State}} = koordinator:dict_findEdgeNodeName(RecordState#recordState.nighborDict, Edge),
      if(State == basic) ->
        %logging(LogDatei, lists:concat([" Edge ist BASIC", timeMilliSecond(),"\n"])),
        NewNodeDict = koordinator:nodeDict_set(Edge,{Values,rejected},RecordState#recordState.nighborDict),
        %logging(LogDatei, lists:concat([" REJECT Neu NewNodeDict ", werkzeug:list2String(dict:to_list(NewNodeDict)) ," ", timeMilliSecond(),"\n"])),
        NewRecordState = RecordState#recordState{nighborDict = NewNodeDict};
        true ->
          %logging(LogDatei, lists:concat([" Edge ist kein BASIC", timeMilliSecond(),"\n"])),
          NewRecordState = RecordState
      end,
      NewNewRecordState = prozTest(NewRecordState,LogDatei),
      logging(LogDatei, lists:concat([" RecordState nighborDict: ", werkzeug:list2String(dict:to_list(NewNewRecordState#recordState.nighborDict))," \n"])),
      loop(NewNewRecordState, LogDatei);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-----REPORT-----%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    {report,Weight,{Edge,Nodex,Nodey}} ->
      %logging(LogDatei, lists:concat([" REPORT RECEIVED von Kante ", Edge ," mit Weight ", Weight, " um ", timeMilliSecond()," \n"])),
      {PEdge, _, _} = RecordState#recordState.inBranch,
      EdgeIsEqual = koordinator:isEdgeEqual(PEdge, Edge),

      case(EdgeIsEqual) of
        false ->
          logging(LogDatei, lists:concat([" REPORT RECEIVED von Kante ", Edge ," mit Weight ", Weight, " um ", timeMilliSecond()," \n"])),
          %logging(LogDatei, lists:concat(["REPORT Edges sind nicht Equal ", timeMilliSecond(),"\n"])),
          NewRecordState = RecordState#recordState{findCount = (RecordState#recordState.findCount - 1) },

          if(Weight < NewRecordState#recordState.bestWeight) ->         %%%%prpfen ob NewRecordState oder RecordState
            %logging(LogDatei, lists:concat([" REPORT neue BestWeight von Kante ", Edge ," um ", timeMilliSecond()," \n"])),
            NewNewRecordState = NewRecordState#recordState{ bestWeight = Weight, bestEdge = {Edge,Nodex,Nodey}};
            true->
              %logging(LogDatei, lists:concat([" REPORT keine neue BestWeight von Kante ", Edge ," um ", timeMilliSecond()," \n"])),
              NewNewRecordState = NewRecordState
          end,

          NewNewNewRecordState = prozReport(NewNewRecordState,LogDatei),
          logging(LogDatei, lists:concat([" RecordState nighborDict: ", werkzeug:list2String(dict:to_list(NewNewNewRecordState#recordState.nighborDict))," \n"])),
          loop(NewNewNewRecordState, LogDatei);

        true ->
          %logging(LogDatei, lists:concat(["REPORT Edges sind Equal ", timeMilliSecond(),"\n"])),

          if(RecordState#recordState.nodeState == find) ->
            Nodi = RecordState#recordState.nodeName,
            Node = global:whereis_name(Nodi),
            %logging(LogDatei, lists:concat([" Nochmal REPORT an sich selbst ", timeMilliSecond(),"\n"])),
            Node ! {report,Weight,{Edge,Nodex,Nodey}},
            loop(RecordState, LogDatei);
            true->
              logging(LogDatei, lists:concat([" REPORT RECEIVED von Kante ", Edge ," mit Weight ", Weight, " um ", timeMilliSecond()," \n"])),
              if(Weight > RecordState#recordState.bestWeight) ->
                %logging(LogDatei, lists:concat([" REPORT Weight > BestWeight ", timeMilliSecond(),"\n"])),
                NewRecordState = prozChangeRoot(RecordState, LogDatei),
                logging(LogDatei, lists:concat([" RecordState nighborDict: ", werkzeug:list2String(dict:to_list(NewRecordState#recordState.nighborDict))," \n"])),
                loop(NewRecordState, LogDatei);
                true->
                  %logging(LogDatei, lists:concat([" REPORT Weight > BestWeight", timeMilliSecond(),"\n"])),
                  if((Weight =:= RecordState#recordState.bestWeight) andalso (Weight =:= infinity)) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-----ENDE Programm-----%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
                    logging(LogDatei, lists:concat([" HALT ", timeMilliSecond(),"\n"])),
                    logging(LogDatei, lists:concat(["NighborDict: ", werkzeug:list2String(dict:to_list(RecordState#recordState.nighborDict)) ," ", timeMilliSecond(),"\n"]));

                    true->
                      %logging(LogDatei, lists:concat([" PROBLEME !!!!!! ", timeMilliSecond(),"\n"])),
                      logging(LogDatei, lists:concat([" RecordState nighborDict: ", werkzeug:list2String(dict:to_list(RecordState#recordState.nighborDict))," \n"])),
                      loop(RecordState, LogDatei)
                  end

              %NewNewNewRecordState = RecordState
              end
          end
      end;
  %startprog(NewNewNewRecordState, LogDatei);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-----CHANGEROOT-----%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    {changeroot,{Edge,_Nodex,_Nodey}} ->
      logging(LogDatei, lists:concat([" CHANGEROOT RECEIVED von Kante ", Edge ," um ", timeMilliSecond()," \n"])),
      NewRecordState = prozChangeRoot(RecordState,LogDatei),
      logging(LogDatei, lists:concat([" RecordState nighborDict: ", werkzeug:list2String(dict:to_list(NewRecordState#recordState.nighborDict))," \n"])),
      loop(NewRecordState, LogDatei);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-----CONNECT-----%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    {connect,Level,{Edge,_Nodex,_Nodey}} ->
      %logging(LogDatei, lists:concat([" CONNECT RECEIVED von Kante ", Edge ," auf Level ", Level, " um ", timeMilliSecond()," \n"])),
      if (RecordState#recordState.nodeState == sleeping) ->
        logging(LogDatei, lists:concat([" WAKEUP über CONNECT um ", timeMilliSecond(),"\n"])),
        %logging(LogDatei, lists:concat([(RecordState#recordState.nodeName), " wacht auf \n"])),
        TempRecordState = prozWakeup(RecordState, LogDatei);
        true ->
          TempRecordState = RecordState%,
          %logging(LogDatei, lists:concat(["CONNECT ist wach um ", timeMilliSecond(),"\n"]))
      end,

      %logging(LogDatei, lists:concat([Level," Level < ", TempRecordState#recordState.level, " recordState.level ", timeMilliSecond(),"\n"])),
      if (Level < TempRecordState#recordState.level) ->
        logging(LogDatei, lists:concat([" CONNECT RECEIVED von Kante ", Edge ," auf Level ", Level, " um ", timeMilliSecond()," \n"])),
        %logging(LogDatei, lists:concat([" CONNECT Level < LevelNode", timeMilliSecond(),"\n"])),
        {ok,{Values,_}} = koordinator:dict_findEdgeNodeName(TempRecordState#recordState.nighborDict, Edge),
        NewNodeDict = koordinator:nodeDict_set(Edge,{Values,branch},TempRecordState#recordState.nighborDict),
        %logging(LogDatei, lists:concat([" CONNECT L<LN Neue  NewNodeDict ", werkzeug:list2String(dict:to_list(NewNodeDict)) ," ", timeMilliSecond(),"\n"])),
        NewRecordState = TempRecordState#recordState{nighborDict = NewNodeDict},

        Nodi = list_to_atom((lists:concat([Values]))),
        Node = global:whereis_name(Nodi),
        Node ! {initiate,NewRecordState#recordState.level,NewRecordState#recordState.fragName,NewRecordState#recordState.nodeState,{Edge,NewRecordState#recordState.nodeName,Values}},
        logging(LogDatei, lists:concat(["INITIATE zu Nodename ", Values ," mit Node ",pid_to_list(Node) ," ", timeMilliSecond(),"\n"])),

        if(NewRecordState#recordState.nodeState == find) ->
          %logging(LogDatei, lists:concat(["CONNECT Node auf State FIND", timeMilliSecond(),"\n"])),
          OldFind_count =  NewRecordState#recordState.findCount,
          NewNewRecodeState =  NewRecordState#recordState{findCount = (OldFind_count + 1) };
          true ->
            %logging(LogDatei, lists:concat([" Node nicht auf State FIND", timeMilliSecond(),"\n"])),
            NewNewRecodeState = NewRecordState
        %startprog(NewNewRecodeState, LogDatei)
        end,
        loop(NewNewRecodeState, LogDatei);

        true ->
          %logging(LogDatei, lists:concat([" CONNECT  Level NICHT KLEINER LevelNode", timeMilliSecond(),"\n"])),
          {ok,{Values,State}} = koordinator:dict_findEdgeNodeName(TempRecordState#recordState.nighborDict, Edge),
          case(State == basic) of
            true ->
              %logging(LogDatei, lists:concat([" Edge ist BASIC", timeMilliSecond(),"\n"])),
              Nodi = TempRecordState#recordState.nodeName,
              Node = global:whereis_name(Nodi),
              %logging(LogDatei, lists:concat([" Nochmal CONNECT an sich selbst", timeMilliSecond(),"\n"])),
              Node ! {connect,Level,{Edge,TempRecordState#recordState.nodeName,Values}},
              loop(TempRecordState, LogDatei);
            false ->
              logging(LogDatei, lists:concat([" CONNECT RECEIVED von Kante ", Edge ," auf Level ", Level, " um ", timeMilliSecond()," \n"])),
              %logging(LogDatei, lists:concat([" Edge keine BASIC ", timeMilliSecond(),"\n"])),
              Nodi = list_to_atom((lists:concat([Values]))),
              Node = global:whereis_name(Nodi),
              logging(LogDatei, lists:concat(["INITIATE mit LEVEL+1 zu Nodename ", Values ," mit Node ",pid_to_list(Node) ," ", timeMilliSecond(),"\n"])),
              Node ! {initiate,(Level + 1),Edge,find,{Edge,TempRecordState#recordState.nodeName,Values}},
              logging(LogDatei, lists:concat([" RecordState nighborDict: ", werkzeug:list2String(dict:to_list(TempRecordState#recordState.nighborDict))," \n"])),
              loop(TempRecordState, LogDatei)
          end
          %loop(TempRecordState, LogDatei)
      end;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-----WAKEUP-----%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    wakeup ->
      if (RecordState#recordState.nodeState == sleeping) ->
        logging(LogDatei, lists:concat([" WAKEUP RECEIVED um ", timeMilliSecond(),"\n"])),
        logging(LogDatei, lists:concat([(RecordState#recordState.nodeName), " wacht von selbst auf \n"])),
        NewRecordState = prozWakeup(RecordState, LogDatei),
        logging(LogDatei, lists:concat([" RecordState nighborDict: ", werkzeug:list2String(dict:to_list(NewRecordState#recordState.nighborDict))," \n"])),
        loop(NewRecordState, LogDatei);
        true ->
          %logging(LogDatei, lists:concat([" WAKEUP RECEIVED aber ist schon wach um ", timeMilliSecond(),"\n"])),
          loop(RecordState, LogDatei)
      end;

    Any -> io:format("Error: Received Something:~p\n", [Any]),
      loop(RecordState, LogDatei)

  end.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-----prozWakeup-----%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
prozWakeup(RecordState, LogDatei)  ->
  %logging(LogDatei, lists:concat([" start PROZWAKEUP ", timeMilliSecond(),"\n"])),
  MinEdge = koordinator:dict_findMinEdge(RecordState#recordState.nighborDict),
  {ok,{Values,_}} = koordinator:dict_findEdgeNodeName(RecordState#recordState.nighborDict, MinEdge),
  %logging(LogDatei, lists:concat([MinEdge, " kleinste Kante mit Nodename ", Values ," ", timeMilliSecond(),"\n"])),
  Nodi = list_to_atom((lists:concat([Values]))),
  Node = global:whereis_name(Nodi),
  NewNodeDict = koordinator:nodeDict_set(MinEdge,{Values,branch},RecordState#recordState.nighborDict),
  %logging(LogDatei, lists:concat([" Neue  NewNodeDict", werkzeug:list2String(dict:to_list(NewNodeDict)) ," ", timeMilliSecond(),"\n"])),
  NewRecordState = RecordState#recordState{nighborDict = NewNodeDict, findCount = 0, nodeState = found},
  logging(LogDatei, lists:concat(["CONNECT von prozWakeup zu Nodename ", Values ," mit Node ",pid_to_list(Node) ," ", timeMilliSecond(),"\n"])),
  Node ! {connect, 0, {MinEdge,NewRecordState#recordState.nodeName,Values}},
  NewRecordState.
%startprog(NewRecordState, LogDatei).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-----prozTest-----%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
prozTest(RecordState, LogDatei)  ->
  %logging(LogDatei, lists:concat([" start PROZTEST ", timeMilliSecond(),"\n"])),
  %logging(LogDatei, lists:concat([" PROZTEST NighborDict ", werkzeug:list2String(dict:to_list(RecordState#recordState.nighborDict)) ," ", timeMilliSecond(),"\n"])),
  ContainBasicEdges = koordinator:dict_containStateEdges(RecordState#recordState.nighborDict, basic),

  if (ContainBasicEdges) ->
    %logging(LogDatei, lists:concat([" PROZTEST ContainBasicEdges = true ", timeMilliSecond(),"\n"])),

    MinEdge = koordinator:dict_findMinEdge( RecordState#recordState.nighborDict, basic),
    {ok,{Values,_}} = koordinator:dict_findEdgeNodeName(RecordState#recordState.nighborDict, MinEdge),
    NewRecordState = RecordState#recordState{ testEdge = MinEdge },
    %logging(LogDatei, lists:concat([MinEdge, " kleinste Kante mit Nodename ", Values ," ", timeMilliSecond(),"\n"])),

    Nodi = list_to_atom((lists:concat([Values]))),
    Node = global:whereis_name(Nodi),
    logging(LogDatei, lists:concat(["TEST von prozTest zu Nodename ", Values ," mit Node ",pid_to_list(Node) ," ", timeMilliSecond(),"\n"])),
    Node ! {test,NewRecordState#recordState.level,NewRecordState#recordState.fragName,{MinEdge,NewRecordState#recordState.nodeName,Values}},

    NewRecordState;

    true->
      %logging(LogDatei, lists:concat([" PROZTEST ContainBasicEdges = false ", timeMilliSecond(),"\n"])),
      TempRecordState = RecordState#recordState{ testEdge = undefined },
      NewRecordState = prozReport(TempRecordState,LogDatei),
      NewRecordState
  end,
  NewRecordState.
%startprog(NewRecordState, LogDatei). %% prüfen ob das sein muss wegen prozReport

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-----prozReport-----%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
prozReport(RecordState, LogDatei)  ->
  %logging(LogDatei, lists:concat([" start prozReport ", timeMilliSecond(),"\n"])),

  if((RecordState#recordState.findCount == 0) and (RecordState#recordState.testEdge == undefined)) ->
    NewRecordState = RecordState#recordState{nodeState = found},
    %{W, _X, _Y} = NewRecordState#recordState.bestEdge,
    {W, _X, _Y} = NewRecordState#recordState.inBranch,
    {ok,{Values,_}} = koordinator:dict_findEdgeNodeName(NewRecordState#recordState.nighborDict, W),
    Nodi = list_to_atom((lists:concat([Values]))),
    Node = global:whereis_name(Nodi),
    logging(LogDatei, lists:concat(["Report von prozReport zu Nodename ", Values ," mit Node ",pid_to_list(Node) ," ", timeMilliSecond(),"\n"])),
%%%%Node ! {report,NewRecordState#recordState.bestWeight,NewRecordState#recordState.bestEdge};    %%% PRÜFEN!!!!!!
    Node ! {report,NewRecordState#recordState.bestWeight,NewRecordState#recordState.inBranch};    %%% PRÜFEN!!!!!!

    true->
      %logging(LogDatei, lists:concat(["NICHT Report ", timeMilliSecond(),"\n"])),
      NewRecordState = RecordState
  end,

  NewRecordState.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%-----prozChangeRoot-----%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
prozChangeRoot(RecordState, LogDatei) ->
  %logging(LogDatei, lists:concat([" start prozChangeRoot ", timeMilliSecond(),"\n"])),
  {W, _X, _Y} = RecordState#recordState.bestEdge,
  {ok,{Values,State}} = koordinator:dict_findEdgeNodeName(RecordState#recordState.nighborDict, W),
  if(State  == branch) ->
    %logging(LogDatei, lists:concat(["prozChangeRoot State ist branch ", timeMilliSecond(),"\n"])),
    Nodi = list_to_atom((lists:concat([Values]))),
    Node = global:whereis_name(Nodi),
    logging(LogDatei, lists:concat(["Changeroot von prozChangroot zu Nodename ", Values ," mit Node ",pid_to_list(Node) ," ", timeMilliSecond(),"\n"])),
    Node ! {changeroot,RecordState#recordState.bestEdge},
    NewRecordState = RecordState;
    true->
      %logging(LogDatei, lists:concat(["prozChangeRoot State ist nicht branch ", timeMilliSecond(),"\n"])),
      Nodi = list_to_atom((lists:concat([Values]))),
      Node = global:whereis_name(Nodi),
      logging(LogDatei, lists:concat(["Connect von prozChangroot zu Nodename ", Values ," mit Node ",pid_to_list(Node) ," ", timeMilliSecond(),"\n"])),
      Node ! {connect,RecordState#recordState.level,RecordState#recordState.bestEdge},
      NewNodeDict = koordinator:nodeDict_set(W,{Values,branch},RecordState#recordState.nighborDict),
      NewRecordState = RecordState#recordState{nighborDict = NewNodeDict}
  end,
  NewRecordState.


